package com.reactim.message.service;

import com.reactim.message.compression.MessageCompressor;
import com.reactim.message.converter.MessageConverter;
import com.reactim.message.dto.MessageResponse;
import com.reactim.message.dto.SendMessageRequest;
import com.reactim.protocol.MessageProto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

/**
 * Protobuf消息服务
 * 提供基于Protobuf协议的消息处理接口
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProtobufMessageService {
    
    private final MessageService messageService;
    private final MessageConverter messageConverter;
    private final MessageCompressor messageCompressor;
    private final com.reactim.message.metrics.ProtobufPerformanceMetrics performanceMetrics;
    
    /**
     * 使用Protobuf协议发送消息（带压缩优化和性能监控）
     */
    public Mono<MessageProto.MessageResponse> sendMessage(MessageProto.SendMessageRequest protoRequest) {
        try {
            // 将Protobuf请求转换为内部DTO（带性能监控）
            SendMessageRequest request = performanceMetrics.recordProtoToEntity("sendMessageRequest", 
                () -> convertProtoToSendRequest(protoRequest));
            
            // 调用内部消息服务
            return messageService.sendMessage(request)
                    .map(messageResponse -> performanceMetrics.recordEntityToProto("messageResponse", 
                        () -> convertToProtoResponse(messageResponse)))
                    .map(this::compressResponseIfNeeded)
                    .doOnSuccess(response -> log.debug("Protobuf消息发送成功: {}", 
                        response.hasMessageData() ? response.getMessageData().getMessageId() : "unknown"));
        } catch (Exception e) {
            log.error("Protobuf消息发送失败", e);
            return Mono.just(MessageProto.MessageResponse.newBuilder()
                    .setCode(MessageProto.ResponseCode.SERVER_ERROR)
                    .setMessage("消息发送失败: " + e.getMessage())
                    .build());
        }
    }
    
    /**
     * 压缩响应消息（如果需要）
     */
    private MessageProto.MessageResponse compressResponseIfNeeded(MessageProto.MessageResponse response) {
        return performanceMetrics.recordCompression(() -> {
            try {
                // 压缩消息数据
                MessageCompressor.CompressedMessage compressed = messageCompressor.compress(response);
                
                // 记录压缩统计
                MessageCompressor.CompressionStats stats = messageCompressor.getCompressionStats(compressed);
                performanceMetrics.recordMessageSize(stats.getOriginalSize(), stats.getCompressedSize());
                
                log.debug("消息压缩统计: {}", stats);
                
                return response; // 这里简化处理，实际可以在协议中添加压缩标识
            } catch (Exception e) {
                log.warn("消息压缩失败，使用原始消息: {}", e.getMessage());
                return response;
            }
        });
    }
    
    /**
     * 将MessageResponse转换为Protobuf响应
     */
    public MessageProto.Message convertToProtoMessage(MessageResponse messageResponse) {
        try {
            // 先转换为实体类，再转换为Protobuf
            var message = messageConverter.fromMessageResponse(messageResponse);
            return messageConverter.toProtoMessage(message);
        } catch (Exception e) {
            log.error("转换为Protobuf消息失败", e);
            // 返回一个基本的Protobuf消息
            return MessageProto.Message.newBuilder()
                    .setMessageId(messageResponse.getMessageId())
                    .setFromUserId(messageResponse.getFromUserId())
                    .setMessageType(MessageProto.MessageType.TEXT)
                    .setStatus(MessageProto.MessageStatus.MSG_NORMAL)
                    .setTimestamp(System.currentTimeMillis() / 1000)
                    .setSequence(messageResponse.getSequence() != null ? messageResponse.getSequence() : 0)
                    .build();
        }
    }
    
    /**
     * 将Protobuf发送请求转换为内部DTO
     */
    private SendMessageRequest convertProtoToSendRequest(MessageProto.SendMessageRequest protoRequest) {
        SendMessageRequest request = new SendMessageRequest();
        
        if (protoRequest.hasMessage()) {
            MessageProto.Message protoMessage = protoRequest.getMessage();
            request.setFromUserId(protoMessage.getFromUserId());
            
            if (protoMessage.getToUserId() != 0) {
                request.setToUserId(protoMessage.getToUserId());
            }
            if (protoMessage.getGroupId() != 0) {
                request.setGroupId(protoMessage.getGroupId());
            }
            
            // 简化的消息类型转换
            request.setMessageType(convertProtoMessageType(protoMessage.getMessageType()));
            
            // 简化的内容转换
            if (protoMessage.hasContent()) {
                request.setContent(convertProtoMessageContent(protoMessage.getContent()));
            }
        }
        
        if (protoRequest.hasOptions()) {
            request.setRequireAck(protoRequest.getOptions().getRequireAck());
        }
        
        return request;
    }
    
    /**
     * 简化的消息类型转换
     */
    private com.reactim.message.entity.Message.MessageType convertProtoMessageType(MessageProto.MessageType protoType) {
        switch (protoType) {
            case TEXT: return com.reactim.message.entity.Message.MessageType.TEXT;
            case IMAGE: return com.reactim.message.entity.Message.MessageType.IMAGE;
            case VOICE: return com.reactim.message.entity.Message.MessageType.VOICE;
            case VIDEO: return com.reactim.message.entity.Message.MessageType.VIDEO;
            case FILE: return com.reactim.message.entity.Message.MessageType.FILE;
            case LOCATION: return com.reactim.message.entity.Message.MessageType.LOCATION;
            case EMOJI: return com.reactim.message.entity.Message.MessageType.EMOJI;
            case CONTACT: return com.reactim.message.entity.Message.MessageType.CONTACT;
            case URL_CARD: return com.reactim.message.entity.Message.MessageType.URL_CARD;
            case REPLY: return com.reactim.message.entity.Message.MessageType.REPLY;
            case FORWARD: return com.reactim.message.entity.Message.MessageType.FORWARD;
            case SYSTEM: return com.reactim.message.entity.Message.MessageType.SYSTEM;
            default: return com.reactim.message.entity.Message.MessageType.TEXT;
        }
    }
    
    /**
     * 简化的消息内容转换
     */
    private com.reactim.message.entity.Message.MessageContent convertProtoMessageContent(MessageProto.MessageContent protoContent) {
        com.reactim.message.entity.Message.MessageContent content = new com.reactim.message.entity.Message.MessageContent();
        
        // 只处理文本消息的简化版本
        if (protoContent.hasText()) {
            com.reactim.message.entity.Message.TextContent textContent = new com.reactim.message.entity.Message.TextContent();
            textContent.setText(protoContent.getText().getText());
            content.setText(textContent);
        }
        
        return content;
    }
    
    /**
     * 将内部响应转换为Protobuf响应
     */
    private MessageProto.MessageResponse convertToProtoResponse(MessageResponse messageResponse) {
        MessageProto.Message protoMessage = convertToProtoMessage(messageResponse);
        
        return MessageProto.MessageResponse.newBuilder()
                .setCode(MessageProto.ResponseCode.SUCCESS)
                .setMessage("消息发送成功")
                .setMessageData(protoMessage)
                .build();
    }
    
    /**
     * 创建新消息推送通知
     */
    public MessageProto.PushNotification createNewMessagePush(MessageResponse messageResponse) {
        return messageConverter.createNewMessagePush(messageResponse);
    }
    
    /**
     * 创建消息撤回推送通知
     */
    public MessageProto.PushNotification createMessageRecallPush(String messageId, Long fromUserId, String reason) {
        return messageConverter.createMessageRecallPush(messageId, fromUserId, reason);
    }
    
    /**
     * 创建已读回执推送通知
     */
    public MessageProto.PushNotification createReadReceiptPush(String messageId, Long readByUserId) {
        return messageConverter.createReadReceiptPush(messageId, readByUserId);
    }
    
    /**
     * 创建输入指示器推送通知
     */
    public MessageProto.PushNotification createTypingIndicatorPush(Long fromUserId, String conversationId, boolean isTyping) {
        return messageConverter.createTypingIndicatorPush(fromUserId, conversationId, isTyping);
    }
    
    /**
     * 创建用户状态变更推送通知
     */
    public MessageProto.PushNotification createUserStatusPush(Long userId, MessageProto.UserStatus oldStatus, 
                                                              MessageProto.UserStatus newStatus, String deviceInfo) {
        return messageConverter.createUserStatusPush(userId, oldStatus, newStatus, deviceInfo);
    }
}